﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xant.FlowEngine.Interface;

namespace Xant.FlowEngine.Core
{
    /// <summary>
    /// 调度器类
    /// </summary>
    internal class ProcessDispatcher
    {
        #region 变量
        protected AbstractProcess process;

        #endregion

        #region 属性

        public AbstractProcess Process
        {
            get
            {
                return process;
            }
        }
        public IEnumerable<AbstractActivity> RunningActivities
        {
            get
            {
                return process.Activities.Where(p => p.Status == Status.Running).ToArray();
            }
        }

        #endregion

        #region 构造函数
        public ProcessDispatcher(AbstractProcess process)
        {
            this.process = process;
            /*流程调度器只捕捉活动对象的状态改变事件，以便激活后续活动节点或是回退到前置活动节点，至于活动对象的状态什么时候改变不是它该管的事*/
            foreach (var activity in process.Activities)
            {
                activity.StatusChanged += activity_StatusChanged;
            }
        }

        #endregion

        #region 公有方法

        public void OnActivityEntry(AbstractActivity activity)
        {

        }

        public void OnActivityCompleted(AbstractActivity activity)
        {
            if(activity.GetType()==typeof(EndActivity))
            {
                throw new NotImplementedException();
            }
            var nextActivities = FindNextActivities(activity, Status.None);
            foreach(var na in nextActivities)
            {
                na.Status = Status.NotStart;
                na.Entry();
            }
        }

        public List<AbstractActivity> FindPrecedeActivities(AbstractActivity activity)
        {
            var list = new List<AbstractActivity>();
            foreach(var transition in process.Transitions.Where(p => p.To.Equals(activity)))
            {
                list.Add(transition.From);
            }
            return list;
        }

        public List<AbstractActivity> FindNextActivities(AbstractActivity activity)
        {
            var list = new List<AbstractActivity>();
            foreach(var transition in process.Transitions.Where(p => p.From.Equals(activity)))
            {
                list.Add(transition.To);
            }
            return list;
        }

        public List<AbstractActivity> FindNextActivities(AbstractActivity activity, Status status)
        {
            var list = new List<AbstractActivity>();
            foreach(var transition in process.Transitions.Where(p => p.From.Equals(activity) && p.To.Status==status))
            {
                list.Add(transition.To);
            }
            return list;
        }

        public JoinActivity FindNextJoinActivity()
        {
            throw new NotImplementedException();

        }

        public SplitActivity FindPrecedeSplitActivity()
        {
            throw new NotImplementedException();

        }
        #endregion

        #region 事件响应
        protected void activity_StatusChanged(AbstractActivity activity)
        {
            if (activity.Status == Status.Completed)
            {
                OnActivityCompleted(activity);
            }
        }

        #endregion

        #region 流程运转相关方法

        /// <summary>
        /// 启动
        /// </summary>
        public void Start()
        {
            var activity = process.StartActivity;
            if (activity == null)
            {
                throw new Exception("流程缺少起始活动");
            }
            if (activity.Status != Interface.Status.NotStart)
            {
                throw new Exception("流程已经启动或是挂起，启动流程失败。");
            }
            activity.Entry();
        }

        /// <summary>
        /// 挂起
        /// </summary>
        public void Suspend()
        {

        }

        /// <summary>
        /// 恢复
        /// </summary>
        public void Resume()
        {

        }

        /// <summary>
        /// 终止
        /// </summary>
        public void Stop()
        {

        }

        #endregion

    }
}
